#include "Nivel.h"
#include <map>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <sstream>
#include <utility>
#include "Button.h"
#include "GoldenStar.h"
#include "MiniBar.h"
#include "Hueco.h"
#include "Servidor.h"
#include <list>
#include "Constantes.h"
#include <string>
#include "Log.h"

Nivel::Nivel() : reglas(board, cantFilas, cantColumnas), maxJugadores(0),
    puntajeRequerido(0) {
    srand(time(0));
    r_seed=0;
}

Nivel::~Nivel() {
    Candy *candy;
    for (int i = 0; i < cantFilas; i++) {
        for (int j = 0; j < cantColumnas; j++) {
            if ((candy = board[i][j]) != NULL) {
                delete candy;
                candy = NULL;
            }
        }
    }

    for (int i = 0; i < cantFilas; i++) {
        delete[] board[i];
    }
    delete[] board;
}


void Nivel::cargarTablero(int nivel) {
    Json::Value root;

    Servidor::getNivel(nivel, root);

    // Tomo los valores caracteristicos del tablero
    cantColumnas = root["cantColumnas"].asInt();
    cantFilas = root["cantFilas"].asInt();
    imagenFondo = root["imagenFondo"].asString();
    maxJugadores = root["maxJugadores"].asInt();
    nombreNivel = root["nombreNivel"].asString();
    puntajeRequerido = root["puntajeRequerido"].asInt();
    sonidoMovimiento = root["sonidoMovimiento"].asString();
    sonidoCombinacion = root["sonidoCombinacion"].asString();

    // Tomo las probabilidades por celda y por columna
    const Json::Value probabilidadesPorCelda =
                                root["probabilidades"]["celda"];
    const Json::Value probabilidadesPorColumna =
                                root["probabilidades"]["columna"];

    probabilidadesCelda[BLUE_BUTTON] =
        probabilidadesPorCelda["button"]["b"].asDouble();
    probabilidadesCelda[GREEN_BUTTON] =
        probabilidadesPorCelda["button"]["g"].asDouble();
    probabilidadesCelda[RED_BUTTON] =
        probabilidadesPorCelda["button"]["r"].asDouble();
    probabilidadesCelda[VIOLET_BUTTON] =
        probabilidadesPorCelda["button"]["v"].asDouble();
    probabilidadesCelda[YELLOW_BUTTON] =
        probabilidadesPorCelda["button"]["y"].asDouble();

    probabilidadesCelda[BLUE_MINIBAR] =
        probabilidadesPorCelda["miniBar"]["b"].asDouble();
    probabilidadesCelda[GREEN_MINIBAR] =
        probabilidadesPorCelda["miniBar"]["g"].asDouble();
    probabilidadesCelda[RED_MINIBAR] =
        probabilidadesPorCelda["miniBar"]["r"].asDouble();
    probabilidadesCelda[VIOLET_MINIBAR] =
        probabilidadesPorCelda["miniBar"]["v"].asDouble();
    probabilidadesCelda[YELLOW_MINIBAR] =
        probabilidadesPorCelda["miniBar"]["y"].asDouble();

    probabilidadesCelda[GOLDENSTAR] =
        probabilidadesPorCelda["goldenStar"].asDouble();

    probabilidadesColumna[BLUE_BUTTON] =
        probabilidadesPorColumna["button"]["b"].asDouble();
    probabilidadesColumna[GREEN_BUTTON] =
        probabilidadesPorColumna["button"]["g"].asDouble();
    probabilidadesColumna[RED_BUTTON] =
        probabilidadesPorColumna["button"]["r"].asDouble();
    probabilidadesColumna[VIOLET_BUTTON] =
        probabilidadesPorColumna["button"]["v"].asDouble();
    probabilidadesColumna[YELLOW_BUTTON] =
        probabilidadesPorColumna["button"]["y"].asDouble();

    probabilidadesColumna[BLUE_MINIBAR] =
        probabilidadesPorColumna["miniBar"]["b"].asDouble();
    probabilidadesColumna[GREEN_MINIBAR] =
        probabilidadesPorColumna["miniBar"]["g"].asDouble();
    probabilidadesColumna[RED_MINIBAR] =
        probabilidadesPorColumna["miniBar"]["r"].asDouble();
    probabilidadesColumna[VIOLET_MINIBAR] =
        probabilidadesPorColumna["miniBar"]["v"].asDouble();
    probabilidadesColumna[YELLOW_MINIBAR] =
        probabilidadesPorColumna["miniBar"]["y"].asDouble();

    probabilidadesColumna[GOLDENSTAR] =
        probabilidadesPorColumna["goldenStar"].asDouble();

    /* Inicializo el tablero */
    board = new Candy **[cantFilas];
    for (int i = 0; i < cantFilas; i++) {
        board[i] = new Candy*[cantColumnas];
    }

    // Tomo las fichas precargadas
    const Json::Value tablero = root["tablero"];

    // Cargo el tablero, según las probabilidades y las fichas fijas
    std::stringstream ss;
    std::string fila, columna;
    std::string candy_str;
    Json::Value candy;
    Candy* o_candy;
    for (int i = 0; i < cantFilas; i++) {
        ss.clear();
        ss << i;
        ss >> fila;
        for (int j = 0; j < cantColumnas; j++) {
            ss.clear();
            ss << j;
            ss >> columna;
            candy = tablero[fila][columna];
            if ((candy_str = candy.asString()).compare("") != 0) {
                o_candy=candyFromString(candy_str);
                board[i][j] = o_candy;
            } else {
                o_candy=   randomCandy(true);
                board[i][j] = o_candy;
            }
        }
    }

    reglas.setCantCols(this->cantColumnas);
    reglas.setCantFilas(this->cantFilas);
    reglas.setTablero(this->board);

    /* Estabilizo el tablero interno (no necesito los json ni los puntos) */
    this->estabilizarTablero(NULL, std::pair<int,int>(-1,-1));
}


void Nivel::imprimirTablero(bool minimo) {
    IElementoTablero *elem = NULL;
    std::string orientacion;
    std::string descripcion_elem;

    /* Para ajustar columnas se fija un tamanio */
    int tam_max_descripcion;
    if (minimo)
        tam_max_descripcion=16;
    else
        tam_max_descripcion=20;
    for (int i = 0; i < cantFilas; i++) {
        std::cout << "[ ";
            for (int j = 0; j < cantColumnas; j++) {
                if ((elem = board[i][j]) == NULL){
                    descripcion_elem= " NONE ";
                } else {
                    // No minimo: imprime color y orientacion.
                    if (!minimo){
                      descripcion_elem= elem->aString(true);
                    } else {
                      descripcion_elem= elem->aString(false);
                    }
                }
                std::string descripcion_tam_fijo(tam_max_descripcion,' ');
                descripcion_tam_fijo.replace(0, descripcion_elem.size(),
                                                            descripcion_elem);
                std::cout << descripcion_tam_fijo;
        }
         std::cout << " ]" << std::endl;
    }
}

/** Descripcion: calcula combinaciones en el tablero actual y aplica las reglas
para cada una de ellas. Luego "aplica gravedad" y rellena con caramelos
aleatorios. Repite estos tres pasos hasta conseguir una configuracion estable.
PRE: si se desea una representacion en formato json debe pasarse una lista por
        parametro. En caso contrario pasar NULL.
POS: se devuelven los tableros procesados en cada ciclo y se retorna la
     cantidad de puntos producto de los mismos. */
int Nivel::estabilizarTablero(Json::Value* listaTableros,
                    std::pair<int,int> destino) {
    Log::loguear(MDEBUG, "Estabilizando tablero...");
    int ciclo = 0, puntos = 0, puntos_ciclo = 0;
    bool habia_huecos = false;
    Json::Value tablero;

    // Repite el proceso hasta conseguir una configuracion estable.
    do {
        if (MODO_DEBUG == 1) {
            std::stringstream ss;
            ss << "<<<<<< INICIO CICLO: " << ciclo << " >>>>>>";
            Log::loguear(MDEBUG, (char *)ss.str().c_str());
            Log::loguear(MDEBUG, "TABLERO ORIGINAL...");
            imprimirTablero(false);
        }
        // Calculo para ver si hay combinaciones desde el principio
        Log::loguear(MDEBUG, "APLICANDO REGLAS...");

        puntos_ciclo = 0;
        puntos_ciclo = aplicarReglas(destino);
        puntos += puntos_ciclo;

        if (puntos_ciclo > 0) {
            if (listaTableros != NULL){
                obtenerJSonTablero(tablero);
                ((*listaTableros)["tableros"]).append(tablero);
            }
            if (MODO_DEBUG == 1)
                imprimirTablero(false);
            /* Una vez obtenidos los tableros se remueve el bit "magico"
               de las fichas que aparecieron como reemplazo de otra. */
            setEstadoEstable();

            Log::loguear(MDEBUG, "APLICANDO GRAVEDAD...");
            aplicarGravedad();
            if (listaTableros != NULL){
                obtenerJSonTablero(tablero);
                ((*listaTableros)["tableros"]).append(tablero);
            }

            if (MODO_DEBUG == 1)
                imprimirTablero(false);

            Log::loguear(MDEBUG, "COMPLETANDO CON CARAMELOS ALEATORIOS...");
            habia_huecos = completarTablero();
            if (listaTableros != NULL && habia_huecos){
                obtenerJSonTablero(tablero);
                ((*listaTableros)["tableros"]).append(tablero);
            }

            if (MODO_DEBUG == 1)
                imprimirTablero(false);
        } else {
            Log::loguear(MDEBUG, "No se hallaron combinaciones...");
        }
        Log::loguear(MDEBUG, ">>>>>> FIN CICLO <<<<<<");
        ciclo++;
    } while (puntos_ciclo > 0);

    return puntos;
}

void Nivel::intercambiar(std::pair<int, int> origen,
        std::pair<int, int> destino){

    Candy *aux = board[origen.first][origen.second];
    board[origen.first][origen.second] = board[destino.first][destino.second];
    board[destino.first][destino.second] = aux;
}

void Nivel::setEstadoEstable(){
    Candy* candy;
    for (int i = 0; i < cantFilas; i++) {
        for (int j = 0; j < cantColumnas; j++) {
            if ((candy = board[i][j]) != NULL)
                candy->setEstable();
        }
    }
}

void Nivel::moverFicha(std::pair<int, int> origen,
        std::pair<int, int> destino, int &puntos, Json::Value& listaTableros) {

    listaTableros.clear();
    if (MODO_DEBUG==1){
        std::stringstream ss;
        ss << "Procesando movimiento: " << std::endl
           << "Origen: " << origen.first << "," << origen.second
           << " (Candy Original) "
           << board[origen.first][origen.second]->getJsonName() << std::endl
           << "Destino: " << destino.first << "," << destino.second
           << " (Candy Original) "
           << board[destino.first][destino.second]->getJsonName();

        Log::loguear(MDEBUG, ss.str());
    }

    /* Intercambio los lugares */
    intercambiar(origen,destino);
    Json::Value tablero;

    /* Las goldenStar las proceso separadas, ya que se activan mediante
       accion directa del jugador */
    Candy* candy= board[destino.first][destino.second];
    if (candy->getJsonName().compare(GOLDENSTAR) == 0 ||
              candy->getJsonName().compare(GOLDENSTAR) == 0) {
        Log::loguear(MDEBUG, "TABLERO CON INTERCAMBIO...");
        if (MODO_DEBUG == 1)
            imprimirTablero(true);
        puntos += reglas.goldenStar(origen, destino);
        obtenerJSonTablero(tablero);
        //std::cout << "Tablero " << tablero.type() << ", Lista: " << listaTableros.type();
        listaTableros["tableros"].append(tablero);
        if (MODO_DEBUG == 1)
            imprimirTablero(true);
        /* Una vez obtenidos los tableros se remueve el bit "magico"
           de las fichas que aparecieron como reemplazo de otra. */
        setEstadoEstable();
        /* Hago caer las fichas y agrego a la lista */
        Log::loguear(MDEBUG, "APLICANDO GRAVEDAD...");
        aplicarGravedad();
        obtenerJSonTablero(tablero);
        listaTableros["tableros"].append(tablero);
        if (MODO_DEBUG == 1)
            imprimirTablero(true);
        /* Completo y agrego a la lista */
        Log::loguear(MDEBUG, "COMPLETANDO TABLERO CON CARAMELOS ALEATORIOS...");
        completarTablero();
        if (MODO_DEBUG == 1)
            imprimirTablero(true);
        obtenerJSonTablero(tablero);
        listaTableros["tableros"].append(tablero);
    }

    puntos += this->estabilizarTablero(&listaTableros,destino);



    /* Si no se generaron combinaciones (mov. invalido) se
       colocan las fichas en sus posiciones originales */
    if (puntos==0)
        intercambiar(destino, origen);
}


void Nivel::obtenerJSonTablero(Json::Value& tablero) {
    std::stringstream ss;
    std::string fila_str;
    std::string color;
    std::string columna_str;
    Json::Value casillero;

    std::string nombre;

    tablero.clear();

    for (int i = 0; i < cantFilas; i++) {
        ss.clear();
        ss.str("");
        ss << i;
        ss >> fila_str;
        for (int j = 0; j < cantColumnas; j++) {
            ss.clear();
            ss.str("");
            ss << j;
            ss >> columna_str;
            casillero.clear();
            if (board[i][j] != NULL) {
                nombre= board[i][j]->getNameAsString();
                if (board[i][j]->orientable())
                  nombre+=board[i][j]->getOrientacion();

                color= board[i][j]->getColorAsString();
                if (board[i][j]->esMagico())
                    casillero["es_magico"]=true;
            } else {
                nombre = DESOCUPADO;
                color = INCOLORO;
            }

            casillero["x"] = i;
            casillero["y"] = j;
            casillero["candy"] = nombre;
            casillero["color"] = color;
            tablero.append(casillero);
        }
    }
}

bool Nivel::movimientoValido(std::pair<int,int> origen, std::pair<int,int> destino) {
    int cantFilas = this->getCantFilas();
    int cantColumnas = this->getCantColumnas();
    /* Verifica si los elementos son "movibles" (huecos no los son) */
    if (!board[origen.first][origen.second]->movible() ||
        !board[destino.first][destino.second]->movible()){
        Log::loguear(MDEBUG, "Elemento no movible!");
        return false;
    }

    /* Verifica si es un movimiento en cruz y adyacente */
    if (origen.first == destino.first) {
      if (origen.second - 1 >= 0 && destino.second == origen.second - 1)
          return true;
      if (origen.second + 1 < cantColumnas && destino.second == origen.second + 1)
          return true;
    }

    if (origen.second == destino.second) {
        if (origen.first  - 1 >= 0 && destino.first == origen.first - 1)
            return true;
        if (origen.first  + 1 < cantFilas && destino.first == origen.first  + 1)
            return true;
    }

return false;
}

/* Para que haya movimientos posibles, tiene que haber 2 fichas pegadas y una
 * a 1 casillero de distancia.
 * Solo chequeo el color porque es suficiente para que haya movimiento posible.
 * POS: devuelve en los parametros el casillero donde se encontró movimiento.
 */
bool Nivel::quedanMovimientos(int &fila, int &columna) {
    fila = -1;
    columna = -1;
    for (int i = 0; i < cantFilas; i++) {
        for (int j = 0; j < cantColumnas - 1; j++) {
            // Si alguna ficha es una golden star hay movimiento
            if (board[i][j]->getJsonName().compare(GOLDENSTAR) == 0) {
                fila = i;
                columna = j;
                return true;
            }

            // Chequeo para las combinaciones horizontales
            if (board[i][j]->getColor() == board[i][j + 1]->getColor()) {
                if ((j + 3 < cantColumnas &&
                     board[i][j]->getColor() == board[i][j + 3]->getColor()) ||
                     (j - 2 > 0 &&
                     board[i][j]->getColor() == board[i][j - 2]->getColor())) {
                    fila = i;
                    columna = j;
                    return true;
                } else if ((i - 1 > 0 && j - 1 > 0 &&
                        board[i][j]->getColor() ==
                        board[i - 1][j - 1]->getColor()) ||
                       (i + 1 < cantFilas && j - 1 > 0 &&
                        board[i][j]->getColor() ==
                        board[i + 1][j - 1]->getColor()) ||
                       (i - 1 > 0 && j + 1 < cantColumnas &&
                        board[i][j]->getColor() ==
                        board[i - 1][j + 1]->getColor()) ||
                       (i + 1 < cantFilas && j + 1 < cantColumnas &&
                        board[i][j]->getColor() ==
                        board[i + 1][j + 1]->getColor())) {
                    fila = i;
                    columna = j;
                    return true;
                }
            }
        }
    }

    // Chequeo para las combinaciones verticales
    for (int i = 0; i < cantFilas - 1; i++) {
     for (int j = 0; j < cantColumnas; j++) {
       // Chequeo para las combinaciones horizontales
       if (board[i][j]->getColor() == board[i + 1][j]->getColor()) {
         if ((i + 3 < cantFilas &&
              board[i][j]->getColor() == board[i + 3][j]->getColor()) ||
              (i - 2 > 0 && board[i][j]->getColor() ==
                                          board[i - 2][j]->getColor())) {
             fila = i;
             columna = j;
             return true;
         } else if ((i - 1 > 0 && j - 1 > 0 &&
                 board[i][j]->getColor() == board[i - 1][j - 1]->getColor()) ||
                (i - 1 > 0 && j + 1 < cantColumnas &&
                 board[i][j]->getColor() == board[i - 1][j + 1]->getColor()) ||
                (i + 1 < cantFilas && j - 1 > 0 &&
                 board[i][j]->getColor() == board[i + 1][j - 1]->getColor()) ||
                (i + 1 < cantFilas && j + 1 < cantColumnas &&
                 board[i][j]->getColor() == board[i + 1][j + 1]->getColor())) {
			 fila = i;
             columna = j;
             return true;
         }
       }
     }
    }

return false;
}

std::string Nivel::getImagenFondo() {
    return imagenFondo;
}

int Nivel::getMaxJugadores() {
    return maxJugadores;
}

bool Nivel::esOrientable(std::string candy, t_orientacion& orientacion,
                             std::string& jsonName){
    int length=candy.length();
    if (candy.find(VERTICAL,length-1)!=std::string::npos){
        jsonName=candy.substr(0,length-1);
        orientacion=VERTICAL;
        return true;
    } else if (candy.find(HORIZONTAL,length-1)!=std::string::npos){
        jsonName=candy.substr(0,length-1);
        orientacion=HORIZONTAL;
        return true;
    }
return false;
}

Candy *Nivel::candyFromString(std::string candy) {
    if (candy.compare(GOLDENSTAR) == 0)
        return new GoldenStar(NONE, candy);

    if (candy.compare(HUECO) == 0)
        return new Hueco(NONE,candy);

    if (candy.compare(BLUE_BUTTON) == 0) {
        return new Button(BLUE, candy);
    } else if (candy.compare(GREEN_BUTTON) == 0) {
        return new Button(GREEN, candy);
    } else if (candy.compare(RED_BUTTON) == 0) {
        return new Button(RED, candy);
    } else if (candy.compare(VIOLET_BUTTON) == 0) {
        return new Button(VIOLET, candy);
    } else if (candy.compare(YELLOW_BUTTON) == 0) {
        return new Button(YELLOW, candy);
    } else {
        t_orientacion orientacion;
        std::string jsonName;
        if (esOrientable(candy,orientacion, jsonName)){
           MiniBar* minibar;
           if (jsonName.compare(BLUE_MINIBAR) == 0) {
               minibar= new MiniBar(BLUE, jsonName);
           } else if (jsonName.compare(GREEN_MINIBAR) == 0) {
               minibar= new MiniBar(GREEN, jsonName);
           } else if (jsonName.compare(RED_MINIBAR) == 0) {
               minibar= new MiniBar(RED, jsonName);
           } else if (jsonName.compare(VIOLET_MINIBAR) == 0) {
               minibar= new MiniBar(VIOLET, jsonName);
           } else if (jsonName.compare(YELLOW_MINIBAR) == 0) {
               minibar= new MiniBar(YELLOW, jsonName);
           }
           minibar->setOrientacion(orientacion);
        return minibar;
        }
    }

return NULL;
}

Candy *Nivel::randomCandy(bool celda) {
    double suma=0, random=0;
    Candy* candy=NULL;
    std::map<std::string, double> probabilidades;
    if (celda) {
        probabilidades = probabilidadesCelda;
    } else {
        probabilidades = probabilidadesColumna;
    }

    random = rand_r(&r_seed) / double(RAND_MAX);

    suma = probabilidades[BLUE_BUTTON];
    if (candy==NULL && random < suma) {
         candy= new Button(BLUE, BLUE_BUTTON);
    }

    suma += probabilidades[BLUE_MINIBAR];
    if (candy==NULL && random < suma) {
        candy= new MiniBar(BLUE, BLUE_MINIBAR);
    }

    suma += probabilidades[GREEN_BUTTON];
    if (candy==NULL && random < suma) {
         candy= new Button(GREEN, GREEN_BUTTON);
    }

    suma += probabilidades[GREEN_MINIBAR];
    if (candy==NULL &&  random < suma) {
        candy= new MiniBar(GREEN, GREEN_MINIBAR);
    }

    suma += probabilidades[RED_BUTTON];
    if (candy==NULL && random < suma) {
         candy= new Button(RED, RED_BUTTON);
    }

    suma += probabilidades[RED_MINIBAR];
    if (candy==NULL &&  random < suma) {
        candy=  new MiniBar(RED, RED_MINIBAR);
    }

    suma += probabilidades[VIOLET_BUTTON];
    if (candy==NULL && random < suma) {
         candy= new Button(VIOLET, VIOLET_BUTTON);
    }

    suma += probabilidades[VIOLET_MINIBAR];
    if (candy==NULL &&  random < suma) {
        candy=  new MiniBar(VIOLET, VIOLET_MINIBAR);
    }

    suma += probabilidades[YELLOW_BUTTON];
    if (candy==NULL && random < suma) {
         candy= new Button(YELLOW, YELLOW_BUTTON);
    }

    suma += probabilidades[YELLOW_MINIBAR];
    if (candy==NULL && random < suma) {
        candy=  new MiniBar(YELLOW, YELLOW_MINIBAR);
    }

    if (candy!=NULL){
        if (random <= PROBABILIDAD_HORIZONTAL){
            ((MiniBar*)candy)->setOrientacion(HORIZONTAL);
        } else {
            ((MiniBar*)candy)->setOrientacion(VERTICAL);
        }
    return candy;
    }

return new GoldenStar(NONE, GOLDENSTAR);
}

bool Nivel::tableroEstable() {
    for (int i = 0; i < (int) cantFilas; i++) {
        for (int j = 0; j < (int) cantColumnas; j++) {
            if (board[i][j] == NULL) {
                return false;
            }
        }
    }
    return true;
}

bool Nivel::aplicarGravedad() {
    bool hubo_burbujeo, reemplazo_superior;
    bool hubo_caidas = false;
    Candy* elem_a_caer;
    int fila_sup;
    do {
        hubo_burbujeo = false;
        for (int i = 1; i < (int)cantFilas; i++) {
            for (int j = 0; j < (int)cantColumnas; j++) {
                /* Si es un hueco no le aplica gravedad*/
                if (board[i][j] && !board[i][j]->movible())
                    continue;
                if (board[i][j] == NULL){
                    reemplazo_superior=false;
                    fila_sup = i-1;
                    while (!reemplazo_superior && fila_sup>=0){
                        elem_a_caer= board[fila_sup][j];
                        if  (elem_a_caer != NULL && elem_a_caer->movible())
                            reemplazo_superior=true;
                        else
                            fila_sup--;
                    }
                    if (reemplazo_superior){
                        /* Intercambio con el de arriba */
                        board[i][j] = elem_a_caer;
                        board[fila_sup][j] = NULL;
                        hubo_burbujeo = true;
                        hubo_caidas = true;
                    }
                }
            }
        }
    } while (hubo_burbujeo);
    return hubo_caidas;
}


bool Nivel::completarTablero() {
    bool habia_huecos = false;

    for (int i = 0; i < (int) cantFilas; i++) {
        for (int j = 0; j < (int) cantColumnas; j++) {
            if (board[i][j] == NULL) {
                board[i][j] = randomCandy(false);
                habia_huecos = true;
            }
        }
    }

    return habia_huecos;
}

int Nivel::aplicarReglas(std::pair<int, int> origen) {
    return reglas.aplicar(origen);
}

int Nivel::getPuntajeRequerido(){
    return puntajeRequerido;
}

int Nivel::getCantColumnas(){
    return cantColumnas;
}

int Nivel::getCantFilas(){
    return cantFilas;
}

std::string Nivel::getNombreNivel(){
    return nombreNivel;
}

std::string Nivel::getSonidoMovimiento(){
    return sonidoMovimiento;
}

std::string Nivel::getSonidoCombinacion(){
    return sonidoCombinacion;
}

void Nivel::setSeed(unsigned int seed){
    r_seed=seed;
}




